package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CategoryClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.IInteractionReplyService;
import jodd.cache.Cache;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author hc
 * @since 2024-08-25
 */
@Service
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final IInteractionReplyService replyService;
    private final UserClient userClient;
    private final SearchClient searchClient;
    private final CourseClient courseClient;
    private final CategoryCache categoryCache;
    private final CatalogueClient catalogueClient;


    /**
     * 用户端新增问题
     *
     * @param questionFormDTO 添加问题表单数据
     */
    @Override
    public void saveQuestion(QuestionFormDTO questionFormDTO) {
        //1、将QuestionFormDTO转成InteractionQuestion
        InteractionQuestion interactionQuestion = BeanUtil.toBean(questionFormDTO, InteractionQuestion.class);

        //2、填充userId
        interactionQuestion.setUserId(UserContext.getUser());

        //3、添加进数据库
        this.save(interactionQuestion);
    }

    /**
     * 用户端分页查询问题
     *
     * @param pageQuery 查询条件
     * @return
     */
    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery pageQuery) {
        //1、校验查询条件
        if(ObjectUtil.isEmpty(pageQuery.getCourseId())&&ObjectUtil.isEmpty(pageQuery.getSectionId())){
            return PageDTO.empty(0L,0L);
        }

        //2、分页查询问题
        Page<InteractionQuestion> questionPage = lambdaQuery()
                .select(InteractionQuestion.class, column -> !column.getColumn().equals("description"))
                .eq(ObjectUtil.isNotEmpty(pageQuery.getCourseId()), InteractionQuestion::getCourseId, pageQuery.getCourseId())
                .eq(ObjectUtil.isNotEmpty(pageQuery.getSectionId()), InteractionQuestion::getSectionId, pageQuery.getSectionId())
                .eq(pageQuery.getOnlyMine(), InteractionQuestion::getUserId, UserContext.getUser())
                .eq(InteractionQuestion::getHidden, false)
                .page(pageQuery.toMpPageDefaultSortByCreateTimeDesc());

        List<InteractionQuestion> records = questionPage.getRecords();
        if(ObjectUtil.isEmpty(records)){
            return PageDTO.empty(questionPage);
        }

        //3、查询结果集中缺少的字段（提问者的数据和最近一次回答的数据）
        //3.1、提取出提问者id和最近一次回答的id
        Set<Long> userIds = new HashSet<>();
        Set<Long> replyIds = new HashSet<>(records.size());
        for (InteractionQuestion record : records) {
            //3.1.1、非匿名的才需要被加入集合
            if(!record.getAnonymity()){
                userIds.add(record.getUserId());
            }
            replyIds.add(record.getLatestAnswerId());
        }

        //3.2、查询最近一次回答的数据,并封装成map
        List<InteractionReply> replyList = replyService.listByIds(replyIds);
        Map<Long,InteractionReply> replyMap = new HashMap<>();
        if(ObjectUtil.isNotEmpty(replyList)){
            for (InteractionReply reply : replyList) {
                replyMap.put(reply.getId(),reply);
                //3.2.1、将回复者id加入userIds集合
                if(!reply.getAnonymity()){
                    userIds.add(reply.getUserId());
                }
            }
        }

        //3.3、查询用户的信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long,UserDTO> userDTOMap = new HashMap<>();
        if(ObjectUtil.isNotEmpty(userDTOS)){
            userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, Function.identity()));
        }


        //4、封装结果集
        List<QuestionVO> list = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionVO questionVO = BeanUtil.toBean(record, QuestionVO.class);
            if(!record.getAnonymity()){
                if(ObjectUtil.isNotEmpty(userDTOMap.get(record.getUserId()))){
                    questionVO.setUserName(userDTOMap.get(record.getUserId()).getName());
                    questionVO.setUserIcon(userDTOMap.get(record.getUserId()).getIcon());
                }
            }

            InteractionReply reply = replyMap.get(record.getLatestAnswerId());
            if(ObjectUtil.isNotEmpty(reply)){
                questionVO.setLatestReplyContent(reply.getContent());
                if(!reply.getAnonymity()){
                    if(ObjectUtil.isNotEmpty(userDTOMap.get(record.getUserId()))){
                        questionVO.setLatestReplyUser(userDTOMap.get(record.getUserId()).getName());
                    }
                }
            }

            list.add(questionVO);

        }


        return PageDTO.of(questionPage,list);
    }

    /**
     * 用户端根据id查询问题详情
     *
     * @param id 问题id
     * @return
     */
    @Override
    public QuestionVO queryById(Long id) {
        //1、根据id查询问题
        InteractionQuestion question = this.getById(id);
        if(ObjectUtil.isEmpty(question)){
            return null;
        }

        //2、根据用户id查询用户信息
        UserDTO userDTO = null;
        if(!question.getAnonymity()){
            userDTO = userClient.queryUserById(question.getUserId());
        }

        //3、封装返回结果
        QuestionVO questionVO = BeanUtil.toBean(question, QuestionVO.class);
        if(ObjectUtil.isNotEmpty(userDTO)){
            questionVO.setUserName(userDTO.getName());
            questionVO.setUserIcon(userDTO.getIcon());
        }

        return questionVO;
    }

    /**
     * 管理端分页查询问题
     *
     * @param pageQuery 查询条件
     * @return
     */
    @Override
    public PageDTO<QuestionAdminVO> queryAdminQuestionPage(QuestionAdminPageQuery pageQuery) {
        //1、通过search服务获取到courseName模糊搜索的courseId集合
        List<Long> courseIds = null;
        if(ObjectUtil.isNotEmpty(pageQuery.getCourseName())){
            courseIds = searchClient.queryCoursesIdByName(pageQuery.getCourseName());
        }

        //2、分页查询问题集合
        Page<InteractionQuestion> page = lambdaQuery()
                .in(ObjectUtil.isNotEmpty(courseIds), InteractionQuestion::getCourseId, courseIds)
                .eq(ObjectUtil.isNotEmpty(pageQuery.getStatus()), InteractionQuestion::getStatus, pageQuery.getStatus())
                .ge(ObjectUtil.isNotEmpty(pageQuery.getBeginTime()), InteractionQuestion::getCreateTime, pageQuery.getBeginTime())
                .le(ObjectUtil.isNotEmpty(pageQuery.getEndTime()), InteractionQuestion::getCreateTime, pageQuery.getEndTime())
                .page(pageQuery.toMpPageDefaultSortByCreateTimeDesc());

        List<InteractionQuestion> records = page.getRecords();
        if(ObjectUtil.isEmpty(records)){
            return PageDTO.empty(page);
        }

        //3、查询需要补全的数据
        //3.1、收集各个需要调用远程接口的id集合（课程id、用户id、章节id）
        Set<Long> cIds = new HashSet<>(records.size());
        Set<Long> userIds = new HashSet<>(records.size());
        Set<Long> catagoryIds = new HashSet<>();
        for (InteractionQuestion record : records) {
            cIds.add(record.getCourseId());
            userIds.add(record.getUserId());
            catagoryIds.add(record.getChapterId());
            catagoryIds.add(record.getSectionId());
        }

        //3.2、获取到课程信息,并转成map集合
        List<CourseSimpleInfoDTO> courseSimpleInfos = courseClient.getSimpleInfoList(courseIds);
        Map<Long, CourseSimpleInfoDTO> courseMap = new HashMap<>(records.size());
        if(ObjectUtil.isNotEmpty(courseSimpleInfos)){
            courseMap = courseSimpleInfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));
        }

        //3.3、获取到用户信息，并转成map集合
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, String> userMap = new HashMap<>(records.size());
        if(ObjectUtil.isNotEmpty(userDTOS)){
            userMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));
        }

        //3.3、获取到章节信息，并转成map集合
        List<CataSimpleInfoDTO> cateSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(catagoryIds);
        Map<Long, String> categoryMap = new HashMap<>(records.size());
        if(ObjectUtil.isNotEmpty(cateSimpleInfoDTOS)){
            categoryMap = cateSimpleInfoDTOS.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));
        }

        //4、开始封装返回的集合
        List<QuestionAdminVO> list = new ArrayList<>(records.size());
        for (InteractionQuestion record : records) {
            QuestionAdminVO questionAdminVO = BeanUtil.toBean(record, QuestionAdminVO.class);

            questionAdminVO.setUserName(userMap.getOrDefault(record.getUserId(),""));

            questionAdminVO.setChapterName(categoryMap.getOrDefault(record.getChapterId(),""));
            questionAdminVO.setSectionName(categoryMap.getOrDefault(record.getSectionId(),""));

            CourseSimpleInfoDTO courseInfo = courseMap.get(record.getCourseId());
            if(ObjectUtil.isNotEmpty(courseInfo)){
                questionAdminVO.setCourseName(courseInfo.getName());
                questionAdminVO.setCategoryName(categoryCache.getCategoryNames(courseInfo.getCategoryIds()));
            }
            list.add(questionAdminVO);

        }

        return PageDTO.of(page,list);
    }


    /**
     * <h1>删除互动问题</h1>
     *
     * @param id
     */
    @Override
    @Transactional
    public void removeQuestion(Long id) {
        if (ObjectUtil.isEmpty(id)) throw  new BizIllegalException("删除互动问题参数错误");
//        查询用户是否删除自己的问题
        InteractionQuestion question = lambdaQuery().eq(InteractionQuestion::getId, id)
                .eq(InteractionQuestion::getUserId, UserContext.getUser()).one();
        if (ObjectUtil.isEmpty(question)) throw new BizIllegalException("这不是你的问题");
//        删除问题
        removeById(id);
//        删除问题下的回答和评论
        replyService.remove(new LambdaQueryWrapper<InteractionReply>()
                .eq(InteractionReply::getQuestionId,id));
    }

    /**
     * <h1>编辑互动问题</h1>
     *
     * @param id
     * @param questionFormDTO
     */
    @Override
    public void changeQuestion(Long id, QuestionFormDTO questionFormDTO) {
//        判断参数是否异常
        if (ObjectUtil.isEmpty(id) && ObjectUtil.isEmpty(questionFormDTO.getTitle()) && ObjectUtil.isEmpty(questionFormDTO.getDescription()) && ObjectUtil.isEmpty(questionFormDTO.getAnonymity()))
            throw new BizIllegalException("编辑互动问题参数错误");
//        编辑问题
        boolean result = lambdaUpdate()
                .set(InteractionQuestion::getTitle, questionFormDTO.getTitle())
                .set(InteractionQuestion::getDescription, questionFormDTO.getDescription())
                .set(InteractionQuestion::getAnonymity, questionFormDTO.getAnonymity())
                .eq(InteractionQuestion::getId, id).update();
//        判断是否编辑成功
        if (!result)throw  new BizIllegalException("编辑互动问题失败");
    }


    /**
     * 管理端根据id查询问题详情
     *
     * @param id 问题id
     * @return
     */
    @Override
    public QuestionAdminVO queryAdminById(Long id) {
        //1、查询问题记录
        InteractionQuestion question = this.getById(id);

        //2、查询需要补全的数据
        //2.1、获取课程信息
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(question.getCourseId(), false, true);
        //2.2、获取提问者和老师信息
        UserDTO userDTO = userClient.queryUserById(question.getUserId());

        List<Long> teacherIds = courseInfo.getTeacherIds();
        List<UserDTO> teacherDTOS = userClient.queryUserByIds(teacherIds);
        StringJoiner teacherName = new StringJoiner(",");
        if (ObjectUtil.isNotEmpty(teacherDTOS)) {
            teacherName = new StringJoiner(",");
            for (UserDTO teacherDTO : teacherDTOS) {
                teacherName.add(teacherDTO.getName());
            }
        }

        //2.3、获取章节信息
        List<CataSimpleInfoDTO> cataInfos = catalogueClient.batchQueryCatalogue(List.of(question.getSectionId(), question.getChapterId()));
        Map<Long, String> cataMap = new HashMap<>();
        if (ObjectUtil.isNotEmpty(cataInfos)) {
            cataMap = cataInfos.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));
        }


        //3、补全结果
        QuestionAdminVO questionAdminVO = BeanUtil.toBean(question, QuestionAdminVO.class);
        questionAdminVO.setTeacherName(teacherName.toString());
        questionAdminVO.setChapterName(cataMap.getOrDefault(question.getChapterId(), ""));
        questionAdminVO.setSectionName(cataMap.getOrDefault(question.getSectionId(), ""));
        if (ObjectUtil.isNotEmpty(userDTO)) {
            questionAdminVO.setUserName(userDTO.getName());
            questionAdminVO.setUserIcon(userDTO.getIcon());
        }
        if (ObjectUtil.isNotEmpty(courseInfo)) {
            questionAdminVO.setCourseName(courseInfo.getName());
            questionAdminVO.setCategoryName(categoryCache.getCategoryNames(courseInfo.getCategoryIds()));
        }

        //4、更新查看状态
        InteractionQuestion question1 = new InteractionQuestion();
        question1.setId(id);
        question1.setStatus(QuestionStatus.CHECKED);
        this.updateById(question1);

        return questionAdminVO;
    }

    /**
     * 管理端隐藏或显示问题 练习二
     *
     * @param id     问题的id
     * @param hidden 是否隐藏
     */
    @Override
    public void showOrHidden(Long id, Boolean hidden) {
        //1、封装要更新的对象
        if (ObjectUtil.isAllNotEmpty(id, hidden)) {
            InteractionQuestion question = new InteractionQuestion().setId(id).setHidden(hidden);
            this.updateById(question);
        }
    }
}
